﻿using System;
using System.Linq;
using System.Linq.Expressions;
using DapperLambdaSQL.Model;
using DapperLambdaSQL.Model.Attributes;
using DapperLambdaSQL.Model.Exceptions;
using DapperLambdaSQL.Utils;

namespace DapperLambdaSQL.BuildSQL
{
    public abstract class SQLBuilder
    {
        public readonly SQLOptions Options;

        public SQLBuilder(SQLOptions options)
        {
            Options = options;
        }

        public string Select<T>() where T : DbModel
        {
            var tableName = ParseTableName<T>();
            return string.Format(SqlKeyWord.Select, SqlKeyWord.FiledAll, tableName);
        }

        public string Select<T, TElement>(Expression<Func<T, TElement>> expression) where T : DbModel
        {
            var tableName = ParseTableName<T>();
            var selectFileds = expression.ParseFileds();
            return string.Format(SqlKeyWord.Select, selectFileds, tableName);
        }

        public string SelectDistinct<T, TElement>(Expression<Func<T, TElement>> expression) where T : DbModel
        {
            var tableName = ParseTableName<T>();
            var selectFileds = expression.ParseFileds();
            return string.Format(SqlKeyWord.SelectDistinct, selectFileds, tableName);
        }

        public string Where<T, TElement>(Expression<Func<T, TElement>> expression, SQLOperator sqlOperator)
        {
            var filedName = expression.ParseFiled();
            if (sqlOperator.IsParame)
            {
                return string.Format(sqlOperator.SqlWhere, filedName);
            }
            return string.Format(sqlOperator.SqlWhere, filedName);
        }

        protected virtual string ParseTableName<T>() where T : DbModel
        {
            var type = typeof(T);
            var attribute = type.GetCustomAttributes(typeof(TableNameAttribute), false).FirstOrDefault();
            var tableName = ((TableNameAttribute)attribute)?.TableName;

            if (string.IsNullOrEmpty(tableName))
            {
                throw new ParseTableNameException();
            }

            switch (Options.DbType)
            {
                case DbType.MySQL:
                    tableName = $"`{tableName}`";
                    break;
                case DbType.Oracle:
                    tableName = $"\"{ tableName}\"";
                    break;
                case DbType.SQLServer:
                    break;
                default:
                    break;
            }
            return tableName;
        }
    }
}